
\section{闰秒是什么？有什么影响}

\href{https://blog.csdn.net/bjweimengshu/article/details/113065067}{程序员小灰 闰秒}

\href{https://cloud.tencent.com/developer/article/1775668}{BAT的乌托邦 GMT UTC}

\href{https://zhuanlan.zhihu.com/p/60070958}{阴历阳历农历}

\subsection{年月日时分秒如何定义}

时间的定义其实和速度息息相关，年月日分别对应着地球，月亮，太阳三个天的运行速度。
对于大多数地区，地球自转一圈即是一天，月球绕地球一圈为一个月，地球绕太阳一圈为一年。

把1天划分成24小时，每小时60分，每分钟60秒，一天共 $24 * 60 * 60 = 864000$ 秒。

把1年划成365天4季12月：春夏秋冬，每季3个月

把1月划分30天：


\subsection{时间修正：闰年，闰月，闰秒，阴历，阳历，农历}

阳历的“阳”，指的是太阳，阳历的一年就是地球围着太阳绕一圈的时间。
阴历的“阴”，指的是月亮，而月亮绕地球运行一周所花费的时间就是阴历的一个月。

实际地球绕太阳一周是365.25天，这样每4年会多一天，就是闰年有366天的由来。

阴历以月亮的阴晴圆缺变化而制定，根据月相确定日期和月份。
一个阴历朔望月平均为29.5306天，12个朔望月为354天或355天，
与阳历回归年（约365.25天）相差11天左右，3年累计的时间差距会超过一个月。

农历是一种以阴历为基础，同时又融合阳历成分而形成的历法，即为阴阳合历。
现行农历置闰方法是“十九年七闰”，即每隔两年到三年，就必须增加一个与上一个月相同的农历月份，增加的这个月叫闰月。

地球自转一周的时间是不稳定的，现在地球越转越慢，会导致一天的时候越来越长。标准秒的时间由TAI原子时来定义。
为了保证实际的时间（自转一周时间的864000分之一）与标准时间一致，大概每隔两三年要将标准时间增加一秒，以保证和实际的地球自转一周时间一致。
由于地球自转的时间无法计算，他有可能变快，也有可能变慢，受到潮汐、天气和熔态金属在地球核心的流动等各方面因素的影响，下一次闰秒的时间无法预估，但是国际地球自转和参考系服务（IERS）会提前6个月公布下一次闰秒的时间。

原子时（TAI）：由于上面描述的世界时并不稳定，物理学家用更为稳定的量子计量的方式来统计时间，1967年，国际计量大会用铯133
（Cs133）原子基态的两个超精细能级之间的跃迁所对应辐射的9192631770个周期所持续的时间定义为1秒，这个是目前最精确的时间
计量方式，其误差为1400000年一秒，基本可忽略不计。

\begin{figure}[htbp]
  \centering
  \includegraphics[width=12cm]{leapsecond}
  \caption{闰秒的调整年份}\label{leapsecond}
\end{figure}

\subsection{闰秒影响处理方式}

闰秒有什么影响？

国际地球自转和参考坐标系统服务（IERS）在2012年6月30日午夜(北京时间7月1号7点59分59秒)增加一闰秒（即出现7：59：60）。由于Linux kernel 2.6.29之前版本存在bug，在进行闰秒调整时可能会引起系统时钟服务ntpd进程死锁。Debian Lenny、RHEL/CentOS 5等旧发行版今天仍被广泛使用，部分供应商早已经发布了补丁。
	但除了Linux服务器外，一些服务器程序也因为闰秒出现了问题，如Reddit、Mozilla、FourSquare、Yelp、LinkedIn和Gawker等网站都短暂遭遇了技术问题，国内的一家云储存供应商发现运行在CentOS 6.2上的Java和MySQL因闰秒出现了不同程度的CPU利用率增长，猜测是JVM和MySQL试图通过CPU硬件晶振的数据获得当前精确的时间，由于闰秒的关系，这个时间和操作系统维持的墙上时间（Wall Time，也就是显示给用户看的时间）不一致，导致了这个问题。简单的修正方法是强制重置系统时间，让系统中所有时间回到同步的状态
	 科学上有两种时间计量系统：基于地球自转的天文测量而得出的“世界时”和以原子振荡周  期确定的“原子时”。“世界时”由于地球自转的不稳定（由地球物质分布不均匀和其它星球的摄动力等引起的）会带来时间的差异，“原子时”（一种较恒定的时制，由原子钟得出）则是相对恒定不变的。这两种时间尺度速率上的差异，一般来说一至二年会差大约1秒时间。
	1971年国际计量大会通过决议：使用“协调世界时”来计量时间。当“协调世界时”和“世界时”之差超过0.9秒时，国际地球自转服务组织（IERS）就负责对“协调世界时”拨快或拨慢1秒，这就是闰秒。


闰秒对linux以及在linux上run的应用的影响


系统打印闰秒插入信息的时候夯住：当NTP通知内核关于闰秒的动作时，这个bug会被触发，这个bug会发生在闰秒发生的前一天的任何时候，

这个bug提前被触发的原因是NTP时间服务器会提前一天通知连接它的linux服务器，将来的某个时刻会发生闰秒，linux服务器的ntp收到这个信息

后会在闰秒时刻对linux的时间做一些处理，增加一秒，或者减去一秒

闰秒活锁导致系统夯住：由于这个bug，NMI看门狗会检测到系统夯住，系统会不停的crash；闰秒被插入后这个bug就会被触发，目前还没确定

哪个版本修复了这个bug

cpu load快速增高：其原因为应用程序不能处理闰秒带来的系统时间的突然变化，linux系统提供两种系统时间，wall time和montonic time，其中

wall time记录的是事实时间，可以向前或者向后调整，montonic time记录的是系统从启动以来的秒数，只能向前递增，因此如果应用程序在获取时间

时用的wall time则会受到系统时间调整（如闰秒）的影响，而采用后者则不会受到影响，具体到jdk来说明在jdk 7u6开始采用后者。



不能处理闰秒的内核在处理闰秒发生故障时会有什么样的系统日志

eg： Kernel panic - not syncing: Watchdog detected hard LOCK UP on cpu 21



闰秒后系统日志会有什么记录？

eg: kernel[81951.244556] Clock: inserting leap second 23:59:60 UTC



内核bug修复情况

以上提到的bug在linux各个版本陆陆续续有修复，这里提供一个安全的版本，内核是2.6.39-200.3或者更高版本的可以认为是安全的



ntp \&\& 闰秒

主机使用了ntp

此时主机在闰秒时的表现将取决于使用的ntp的版本

1 版本高于等于4.2.2p1-9 或者更高版本（除了ntp-4.2.6p5-19.el7, ntp-4.2.6p5-1.el6 and ntp-4.2.6p5-2.el6\_6）

a 带-x参数运行：闰秒不是直接在内核中添加，而是把这一秒分散到大约2000秒中，1秒比之前长一些，缓慢的更改时间，

这样做的优点：


1）避免时间倒退造成的应用逻辑问题

2）比较奇怪的时间点23:59:60不会出现

3）由于实际上没有增加闰秒，所以上面描述的内核bug也不会出现

这样做的缺点：

1）由于调整的时间段内，一秒的长短实际上是不准确的，所以对时间精度要求高的场景就不适用了

2）由于ntp的更新机制，这个办法同样也不适用于那些要求所有节点时间一致的集群

b 不带-x参数运行，ntp会通知内核直接增加一秒(是突增的，非连续的)

2 版本低于4.2.2p1-9

　　ntp会通知内核直接增加一秒，或者在停止一秒

注意：如果主机上运行了ntp，那么运行“file /etc/localtime”，确保输出结果中有“no leap seconds”（这表明不会添加闰秒）

主机没有使用ntp

1 没有使用tzdata

　　那么主机的时间完全由自己调整，建议使用ntp加上-x参数

2 使用了tzdata

　　a 版本低于2015a，不会添加闰秒

　　b 大于等于2015a，并且运行“file /etc/localtime”，输出结果中有“X leap seconds”（X是个数字）

　　　那么闰秒会以“23:59:60”这样的形式出现，这会导致DATE/TIMESTAMP数据类型出现问题，

　　　你需要复制适当的/usr/share/zoneinfo文件覆盖/etc/localtime（这个操作是动态调整的，不需要重启）



应对闰秒的总结

1 升级内核使版本大于等于2.6.39-200.3，内核能够处理闰秒，但是依然要提防应用程序对时间的敏感度，具体情况可参考这个，

针对这样的应用程序，你需要

a 重构代码

b 升级对应的软件如jdk

2 在主机是任何版本内核的情况下，升级ntp是版本大于等于4.2.2p1-9，来应对那些对时间精度要求不高的场景

3 对于那些既不关心时间精度，也不想升级任何东西的，那就重启ntp

  a 在上级时间服务器发闰秒通知开始之前停止ntp（需提前一天 /etc/init.d/ntpd stop），

  b date -s "`date`" （重置系统时间，个人认为这样做可能是为了解开闰秒造成的死锁）

  c 启动ntp/etc/init.d/ntpd start

4 copy时间文件应对tzdata添加的闰秒


虽然闰秒对普通人的日常生活没有任何影响，但是对于开启NTP服务的Linux系统来说有致命的风险，在Linux kernel 2.6.29之前版本存在bug，在进行闰秒调整时可能会引起系统导致ntpd进程死锁，从而导致crash。另外由于应用程序不能处理闰秒的问题导致时间的变化，会导致CPU load激增。

在上一次闰秒产生，国外Reddit、Mozilla、FourSquare、Yelp、LinkedIn和Gawker都产生了一定的问题，其中Reddit宕机时间超过1个半小时。其中，或许你能很明显的看到异常错误信息：kernel[81951.244556] Clock: inserting leap second 23:59:60 UTC

另外，针对数据库方面，23:59:60时间的问题兼容也不尽相同。

PostgreSQL：PostgreSQL可以兼容23:59:60的写法，不会报错。

Mysql：Mysql还不支持60秒写法，闰秒时必须使用unix time来表示时间，否则会报错。

根据目前的信息来看，Linux内核版本高于2.6.29修复了这个问题，NTP版本高于4.2.2p1-9会把这一秒的时间分散到大约2000秒中，低于该版本的话则会直接加一秒或者减一秒。

解决方案
最简单直接的方法就是闰秒发生前停止ntpd服务，闰秒结束后再开启。

提前一天停止ntp /etc/init.d/ntpd stop
重置系统时间 date -s "`date`"
重新开启ntp ntp/etc/init.d/ntpd start

但是有一个很明显的问题就是，大公司一个服务上千台机器，操作起来成功太高，而且停止同步是否会带来其他的问题不好评估影响面。

目前像google、阿里、amazon都有一些具体的应对方案，使用云服务的话可能不需要用户关心这方面的问题，如果是自己机房托管的话那么可能需要运维开发人员手动处理了。

以国内阿里云的处理方案举例，amazon同样也是采用该方案

阿里云的ECS云服务器的NTP服务采用忽略闰秒时刻的跳秒，缓慢同步消除闰秒带来的1秒误差的方案来面对闰秒事件，实际上采用的方案是闰秒发生前，每秒比UTC慢1/86400，经过12小时（43200秒）后，会比UTC慢0.5秒，闰秒发生之后，每秒和UTC误差减少1/86400，经过12小时（43200秒）后，-0.5的误差消除。国外Amazon也是这样的解决方案。





